package com.taobao.ued.toy.dao;

import com.taobao.ued.toy.domain.Designer;
import com.taobao.ued.toy.domain.FollowRelation;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Repository
public class JdbcFollowRelationDao implements FollowRelationDao {

	Log logger = LogFactory.getLog(getClass());
	private SimpleJdbcTemplate jdbcTemplate;

	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

	private SimpleJdbcTemplate getSimpleJdbcTemplate() {
		return this.jdbcTemplate;
	}

	static String[] FIELDS = new String[]{
			"designerId",
			"followingId",
			"acknowledgement"
	};

	static String[] PARAMS = DaoUtils.getFieldsForParams(FIELDS);


	private DesignerDao designerDao;

	@Autowired
	public void setDesignerDao(DesignerDao designerDao) {
		this.designerDao = designerDao;
	}

	public void add(FollowRelation d) throws Exception {
		logger.info("add follow: " + d.getDesignerId() + " -> " + d.getFollowingId());

		MapSqlParameterSource params = DaoUtils.getParamSource(d, FIELDS);
		int count = getSimpleJdbcTemplate().update(
				"insert into followRelations (" + StringUtils.join(FIELDS, ",") + ") " +
						"values (" + StringUtils.join(PARAMS, ",") + ")", params);

		logger.info("Rows affected: " + count);
	}


	public void delete(FollowRelation d) throws Exception {
		logger.info("delete follow: " + d.getDesignerId() + " -> " + d.getFollowingId());
		MapSqlParameterSource params = DaoUtils.getParamSource(d, FIELDS);
		int count = getSimpleJdbcTemplate().update(
				"delete from followRelations where designerId = :designerId " +
						"and followingId = :followingId",
				params);
		logger.info("Rows affected: " + count);
	}

	public int _getFollowersCount(String followingId, int acknowledgement) throws Exception {
		return getSimpleJdbcTemplate().queryForInt("select count(*)" +
				" from followRelations " +
				"where followingId = :followingId and acknowledgement = :acknowledgement",
				new MapSqlParameterSource().addValue("followingId", followingId)
						.addValue("acknowledgement", acknowledgement));
	}


	public int getNotAckFollowersCount(String followingId) throws Exception {
		return _getFollowersCount(followingId, 0);
	}

	public int getFollowersCount(String followingId) throws Exception {
		return _getFollowersCount(followingId, 1);

	}

	public int getFollowingsCount(String designerId) throws Exception {
		return getSimpleJdbcTemplate().queryForInt("select count(*)" +
				" from followRelations " +
				"where designerId = :designerId  and acknowledgement = 1 ",
				new MapSqlParameterSource().addValue("designerId", designerId));
	}


	public void acknowledgement(FollowRelation d) throws Exception {
		logger.info("update follow: " + d.getDesignerId() + " -> " + d.getFollowingId() + " -> " + d.getAcknowledgement());
		MapSqlParameterSource params = DaoUtils.getParamSource(d, FIELDS);
		int count = getSimpleJdbcTemplate().update(
				"update followRelations set acknowledgement = 1 " +
						"where designerId = :designerId and followingId = :followingId",
				params);
		logger.info("Rows affected: " + count);
	}

	public List<Designer> getFollowings(String designerId, int start, int end) throws Exception {
		logger.info("get followings: " + designerId);
		List<FollowRelation> followings = getSimpleJdbcTemplate().query("select * from followRelations " +
				"where designerId = :designerId and acknowledgement=1 limit :start , :end",
				new FollowMapper(),
				new MapSqlParameterSource().addValue("designerId", designerId)
						.addValue("start", start)
						.addValue("end", end));
		if (followings.size() == 0) return new ArrayList<Designer>();
		List<String> ids = new ArrayList<String>();
		for (FollowRelation fr : followings) {
			ids.add(fr.getFollowingId());
		}
		return designerDao.gets(ids);
	}

	public List<Designer> getNotAckFollowers(String followingId, int start, int end) throws Exception {
		return this._getFollowers(followingId, start, end, 0);
	}

	public List<Designer> getFollowers(String followingId, int start, int end) throws Exception {
		return this._getFollowers(followingId, start, end, 1);
	}


	public List<Designer> _getFollowers(String followingId, int start, int end, int acknowledgement) throws Exception {
		logger.info("get followers: " + followingId);
		List<FollowRelation> followings = getSimpleJdbcTemplate().query("select *" +
				" from followRelations " +
				"where followingId = :followingId and acknowledgement=:acknowledgement limit :start , :end",
				new FollowMapper(),
				new MapSqlParameterSource().addValue("followingId", followingId)
						.addValue("acknowledgement", "acknowledgement")
						.addValue("start", start)
						.addValue("end", end));
		if (followings.size() == 0) return new ArrayList<Designer>();
		List<String> ids = new ArrayList<String>();
		for (FollowRelation fr : followings) {
			ids.add(fr.getDesignerId());
		}
		return designerDao.gets(ids);
	}

	static class FollowMapper implements ParameterizedRowMapper<FollowRelation> {

		public FollowRelation mapRow(ResultSet rs, int rowNum) throws SQLException {
			FollowRelation prod = new FollowRelation();
			try {
				DaoUtils.copyBeanFromRs(prod, rs, FIELDS);
			} catch (Exception e) {
				throw new SQLException(e);
			}
			return prod;
		}

	}

}